#coding:utf-8
#######################################################################################
#
#     程序名称：2048
#             作者：段再续
#     环境：Windows 10
#     Python版本：2.7      32位
#     Pygame版本：1.9.2a   32位
#     最后修改日期：2016.11.12  21：39            
#
###########版本V1.0#####################################################################
#
#  1.0:
#      1.2048是一款非常益智的游戏
#      2.游戏初步完成
#
########################################################################################
import random
from sys import exit
from copy import deepcopy
import pygame
from pygame.locals import *
from math import pi
########################################################################################
#youxi = [[0]*4]*4 #记录每个格子的数字
#youxi = [[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]]
youxi = [([0] * 4) for i in range(4)]   #
you = [([0] * 4) for i in range(4)]     #副本，用于判断按键是否能生效
score = 0         #成绩
X = 0##########################################
Y = 3##    记录随机产生新数字的位置           ##
K = 1##########################################
M = 0           ####如果游戏结束，让M=0，不执行接受上下左右按键，避免游戏陷入死循环
maxscore = 0    ###最高分
#########################################################################################

def shua():####################################绘制页面##################################
    screen.fill((176,176,176))############填充整个窗口
    fenshu()                  ############计算分数
    pygame.draw.rect(screen,(247,252,246),Rect(0,200,500,500))############下方游戏区域背景
    font=pygame.font.Font("simhei.ttf", 50)                   ############上方区域提示内容
    text_surface = font.render(u"2048", True, (39,96,151))    #左半部
    screen.blit(text_surface, (50, 0))
    font=pygame.font.Font("simhei.ttf", 40)
    text_surface = font.render(u"方向键控制", True, (39,96,151)) 
    screen.blit(text_surface, (50, 50))
    text_surface = font.render(u"空格重来", True, (39,96,151)) 
    screen.blit(text_surface, (50, 100))
    text_surface = font.render(u"ESC退出", True, (39,96,151)) 
    screen.blit(text_surface, (50, 150))
    font=pygame.font.Font("simhei.ttf", 20)                    #右半部
    text_surface = font.render(u"得分：%s"%(score), True, (0, 0, 0))
    screen.blit(text_surface, (300, 50))
    text_surface = font.render(u"最高分：%s"%(maxscore), True, (0, 0, 0))
    screen.blit(text_surface, (300, 150))
    for i in xrange(1,6):#######################绘制游戏区域##########################
        pygame.draw.line(screen,(0,0,0),(50,150+(i*100)),(450,150+(i*100)),3)
    for i in xrange(1,6):
        pygame.draw.line(screen,(0,0,0),(-50+(i*100),250),(-50+(i*100),650),3)
    for i in xrange(0,4):
        for j in xrange(0,4):
            if youxi[i][j]==0:############跳过输出值为0的区域
                continue
            font=pygame.font.Font("simhei.ttf", 40)
            text_surface = font.render(u"%s"%(youxi[i][j]), True, (0, 0, 0))
            screen.blit(text_surface, (55+j*100, 305+i*100))
    if jieshu()==0:############游戏结束############
        pygame.draw.rect(screen,(176,176,176),Rect(0,0,500,200))
        font=pygame.font.Font("simhei.ttf", 20)
        text_surface = font.render(u"得分：%s"%(score), True, (0, 0, 0))
        screen.blit(text_surface, (300, 50))
        text_surface = font.render(u"最高分：%s"%(maxscore), True, (0, 0, 0))
        screen.blit(text_surface, (300, 150))
        font=pygame.font.Font("simhei.ttf", 50)
        text_surface = font.render(u"2048", True, (39,96,151)) 
        screen.blit(text_surface, (50, 0))
        font=pygame.font.Font("simhei.ttf", 40)
        text_surface = font.render(u"你输了！！！", True, (248,124,72)) 
        screen.blit(text_surface, (50, 50))
        text_surface = font.render(u"空格重来", True, (39,96,151)) 
        screen.blit(text_surface, (50, 100))
        text_surface = font.render(u"ESC退出", True, (39,96,151)) 
        screen.blit(text_surface, (50, 150))
    elif jieshu()==2048:############赢了########
        pygame.draw.rect(screen,(176,176,176),Rect(0,0,500,000))
        font=pygame.font.Font("simhei.ttf", 20)
        text_surface = font.render(u"得分：%s"%(score), True, (0, 0, 0))
        screen.blit(text_surface, (300, 50))
        text_surface = font.render(u"最高分：%s"%(maxscore), True, (0, 0, 0))
        screen.blit(text_surface, (300, 150))
        font=pygame.font.Font("simhei.ttf", 50)
        text_surface = font.render(u"2048", True, (39,96,151)) 
        screen.blit(text_surface, (50, 0))
        font=pygame.font.Font("simhei.ttf", 40)
        text_surface = font.render(u"恭喜您！！！", True, (248,124,72)) 
        screen.blit(text_surface, (50, 50))
        text_surface = font.render(u"空格重来", True, (39,96,151)) 
        screen.blit(text_surface, (50, 100))
        text_surface = font.render(u"ESC退出", True, (39,96,151)) 
        screen.blit(text_surface, (50, 150))
    pygame.display.update()#刷新
def suiji():####################################随机数，随机一个坐标和产生的随机数值####################################
    global X
    global Y
    global K
    X = random.randint(0,3)
    Y = random.randint(0,3)
    K = random.randint(0,3)
def newNum():####################################依据随机产生的做表和随机数值来给没有值的区域赋值##############################
    while True:
        if youxi[Y][X]==0:
            if K==1 or K==0 or K==2:
                youxi[Y][X]=2
                suiji()
                break
            else:
                youxi[Y][X]=4
                suiji()
                break
        else:
            suiji()
def cun():#################################保存按键前的list状态#############################
    for i in xrange(0,4):
        for j in xrange(0,4):
            you[i][j]=youxi[i][j]
def chong():##############比较按键前后list是否发生改变，如果没有改变，则此次按键不产生新的数###
    for i in xrange(0,4):
        for j in xrange(0,4):
            if you[i][j]!=youxi[i][j]:
                return 1
def left():####################################向左计算####################################
    global score
    cun()
    for y in xrange(0,4):
        i = 0
        for x in xrange(0,4):#############第一个循环清除掉数字间的空值区域
            if youxi[y][x]!=0:
                youxi[y][i]=youxi[y][x]
                if i!=x:
                    youxi[y][x]=0
                i+=1
        i=0
        for i in xrange(0,3):#############计算分数，并让list各行从左到右重新排列
            if youxi[y][i]==youxi[y][i+1]:
                youxi[y][i]=youxi[y][i]+youxi[y][i]
                score +=youxi[y][i]
                youxi[y][i+1]=0
        i=0
        for x in xrange(0,4):############再次清楚数字间的空值区域
            if youxi[y][x]!=0:
                youxi[y][i]=youxi[y][x]
                if i!=x:
                    youxi[y][x]=0
                i+=1
    suiji()
    if chong()==1:
        newNum()
def right():####################################向右计算####################################
    global score
    cun()
    for y in xrange(0,4):
        i = 3
        for x in xrange(3,-1,-1):#############第一个循环清除掉数字间的空值区域
            if youxi[y][x]!=0:
                youxi[y][i]=youxi[y][x]
                if i!=x:
                    youxi[y][x]=0
                i-=1
        i=3
        for i in xrange(3,0,-1):#############计算分数，并让list各行从右到左重新排列
            if youxi[y][i]==youxi[y][i-1]:
                youxi[y][i]+=youxi[y][i]
                score +=youxi[y][i]
                youxi[y][i-1]=0
        i=3
        for x in xrange(3,-1,-1):############再次清楚数字间的空值区域
            if youxi[y][x]!=0:
                youxi[y][i]=youxi[y][x]
                if i!=x:
                    youxi[y][x]=0
                i-=1
    suiji()
    if chong()==1:
        newNum()
def up():####################################向上的计算####################################
    global score
    cun()
    for x in xrange(0,4):
        i = 0
        for y in xrange(0,4):#############第一个循环清除掉数字间的空值区域
            if youxi[y][x]!=0:
                youxi[i][x]=youxi[y][x]
                if i!=y:
                    youxi[y][x]=0
                i+=1
        i=0
        for i in xrange(0,3):#############计算分数，并让list各行从上到下重新排列
            if youxi[i][x]==youxi[i+1][x]:
                youxi[i][x]+=youxi[i][x]
                score +=youxi[i][x]
                youxi[i+1][x]=0
        i=0
        for y in xrange(0,4):############再次清楚数字间的空值区域
            if youxi[y][x]!=0:
                youxi[i][x]=youxi[y][x]
                if i!=y:
                    youxi[y][x]=0
                i+=1
    suiji()
    if chong()==1:
        newNum()
def down():####################################向下的计算####################################
    global score
    global C
    cun()
    for x in xrange(0,4):
        i = 3
        for y in xrange(3,-1,-1):#############第一个循环清除掉数字间的空值区域
            if youxi[y][x]!=0:
                youxi[i][x]=youxi[y][x]
                if i!=y:
                    youxi[y][x]=0
                i-=1
        i=3
        for i in xrange(3,0,-1):#############计算分数，并让list各列从下到上重新排列
            if youxi[i][x]==youxi[i-1][x]:
                youxi[i][x]+=youxi[i][x]
                score +=youxi[i][x]
                youxi[i-1][x]=0
        i=3
        for y in xrange(3,-1,-1):############再次清楚数字间的空值区域
            if youxi[y][x]!=0:
                youxi[i][x]=youxi[y][x]
                if i!=y:
                    youxi[y][x]=0
                i-=1
    suiji()
    if chong()==1:
        newNum()
def jieshu():######################判断游戏是否已经结束################
    global M
    i = 0
    j = 0
    num = 0
    M=0
    for i in xrange(0,4):#############如有2048产生，代表游戏赢了，直接返回2048
        for j in xrange(0,4):
            if youxi[i][j]==2048:
                return 2048
    for i in xrange(0,4):#############如有空区域，代表游戏还可以继续进行，返回1
        for j in xrange(0,4):
            if youxi[i][j]==0:
                M+=1
                return 1
    for i in xrange(0,4):############################如果没空区域，也没2048产生，判断相邻两个区域是否存在相等的数值，如果没有，代表游戏输了，返回0
        for j in xrange(0,4):
            if i==0:#######上边线####
                if j==0:
                    if youxi[i][j]==youxi[i][j+1] or youxi[i][j]==youxi[i+1][j]:#左上角（与相邻两个区域比较）
                        num+=1
                elif j==3:
                    if youxi[i][j]==youxi[i][j-1] or youxi[i][j]==youxi[i+1][j]:#右上角（与相邻两个区域比较）
                        num+=1
                else:
                    if youxi[i][j]==youxi[i][j-1] or youxi[i][j]==youxi[i+1][j] or youxi[i][j]==youxi[i][j+1]:#中间的俩区域（与相邻三个区域比较）
                        num+=1
            elif i==3:#####下边线####
                if j==0:
                    if youxi[i][j]==youxi[i][j+1] or youxi[i][j]==youxi[i-1][j]:#左下角（与相邻两个区域比较）
                        num+=1
                elif j==3:
                    if youxi[i][j]==youxi[i][j-1] or youxi[i][j]==youxi[i-1][j]:#右下角（与相邻两个区域比较）
                        num+=1
                else:
                    if youxi[i][j]==youxi[i][j-1] or youxi[i][j]==youxi[i-1][j] or youxi[i][j]==youxi[i][j+1]:#中间的俩区域（与相邻三个区域比较）
                        num+=1
            else:   ########第2、3行###
                if j==0:
                    if youxi[i][j]==youxi[i+1][j] or youxi[i][j]==youxi[i-1][j] or youxi[i][j]==youxi[i][j+1]:#左边中间的俩区域（与相邻三个区域比较）
                        num+=1
                elif j==3:
                    if youxi[i][j]==youxi[i+1][j] or youxi[i][j]==youxi[i-1][j] or youxi[i][j]==youxi[i][j-1]:#右边中间的俩区域（与相邻三个区域比较）
                        num+=1
                else:
                    if youxi[i][j]==youxi[i][j-1] or youxi[i][j]==youxi[i-1][j] or youxi[i][j]==youxi[i+1][j] or youxi[i][j]==youxi[i][j+1]:#中间的4个区域（与相邻四个区域比较）
                        num+=1
    if num==0:####如果游戏结束，让M=0，不执行接受上下左右按键，避免游戏陷入死循环
        M = 0
    return num
def fenshu():#######################计算分数#############################
    global score
    global maxscore
    if maxscore < score:          #取最高分
        maxscore = score
    f = open('f.txt','r+')        #第一次打开，读取历史最高分
    a = f.readline()
    a = int(a)
    if a > maxscore:              #取最高分
        maxscore = a
    f.close()
    f = open('f.txt','w')         #第二次打开，利用'W'打开已存在文件的清空功能，并写入当前最高分
    f.write('%s'%(maxscore))
    f.close()
def newGame():#######################开始新一局的游戏，数据归零#############################
    global M
    global score
    M = 0                      ###################
    score = 0                  #                 #
    for i in xrange(0,4):      #    数据归零      #
        for j in xrange(0,4):  #                 #
            youxi[i][j]=0      ###################
    newNum()
    newNum()#初始化创建两个数
    shua()
    newKey()
def newKey():
    global M
    global score
    score = 0         #成绩
    while True:
        for event in pygame.event.get():          ####获取按键参数
            if event.type == QUIT:
                exit()
            if event.type == KEYUP:
                if event.key == K_ESCAPE:         #####程序结束
                    pygame.quit()
                    exit()
                elif event.key == K_SPACE:        ######开始新游戏，重来
                    newGame()
                elif M==0 and jieshu()==0:        ####如果相邻区域没有相等的值，且没有空区域了，代表游戏结束，不接受上下左右按键
                    suiji()                       ####无意义，满足语法
                elif jieshu()==2048:              ####如果2048产生，代表游戏结束，不接受上下左右按键
                    suiji()                       ####无意义，满足语法
                else:
                    if event.key == 273:          #上
                        up()
                    elif event.key == 274:        #下
                        down()
                    elif event.key == 276:        #左
                        left()
                    elif event.key == 275:        #右
                        right()           
        shua()                                    #刷新界面
pygame.init()   ###开始
window = Rect(0,0,500,700)
screen = pygame.display.set_mode(window.size, 0)######打开窗口
newGame()####新游戏
exit()######程序结束

